home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc Development Framework / ODFDev / ODF / OS / FWGraphx / Sources / FWTxtBuf.cpp < prev    next >
Encoding:
Text File  |  1995-11-08  |  12.3 KB  |  498 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWTxtBuf.h
  4. //    Release Version:    $ 1.0d11 $
  5. //    Modified by MEB to support non-single-byte characters
  6. //
  7. //    Copyright:    © 1993, 1995 by Apple Computer, Inc., all rights reserved.
  8. //
  9. //========================================================================================
  10.  
  11. #include "FWOS.hpp"
  12.  
  13. #ifndef FWTXTBUF_H
  14. #include "FWTxtBuf.h"
  15. #endif
  16.  
  17. #ifndef FWMEMORY_H
  18. #include "FWMemory.h"
  19. #endif
  20.  
  21. #if FW_LIB_EXPORT_PRAGMAS
  22. #pragma lib_export on
  23. #endif
  24.  
  25. //========================================================================================
  26. //    RunTime Info
  27. //========================================================================================
  28.  
  29. #ifdef FW_BUILD_MAC
  30. #pragma segment FWGraphx_TextBuf
  31. #endif
  32.  
  33. //========================================================================================
  34. //    Static Initialization
  35. //========================================================================================
  36.  
  37. #define FW_kStaticBufferSize 256
  38. #define    FW_kDynamicBufferSizeIncrement 256
  39.  
  40. FW_Byte FW_CPrivTextBuffer::gStaticBuffer[FW_kStaticBufferSize];
  41. unsigned short FW_CPrivTextBuffer::gStaticBufferUseCount = 0;
  42.  
  43. //========================================================================================
  44. // CLASS FW_CPrivTextBuffer
  45. //========================================================================================
  46.  
  47. //----------------------------------------------------------------------------------------
  48. // FW_CPrivTextBuffer::FW_CPrivTextBuffer
  49. //----------------------------------------------------------------------------------------
  50.  
  51. FW_CPrivTextBuffer::FW_CPrivTextBuffer(const FW_CString* string) :
  52.     fString(string),
  53.     fReader(NULL),
  54.     fCurrentLine(NULL),
  55.     fIsDone(FALSE),
  56.     fDynamicBufferBase(NULL)
  57. {
  58.     gStaticBufferUseCount ++;
  59.  
  60.     GetNextLine();
  61.     FW_END_CONSTRUCTOR
  62. }
  63.     
  64. //----------------------------------------------------------------------------------------
  65. // FW_CPrivTextBuffer::FW_CPrivTextBuffer
  66. //----------------------------------------------------------------------------------------
  67.  
  68. FW_CPrivTextBuffer::FW_CPrivTextBuffer(FW_CTextReader* reader) :
  69.     fString(NULL),
  70.     fReader(reader),
  71.     fCurrentLine(NULL),
  72.     fIsDone(FALSE),
  73.     fDynamicBufferBase(NULL)
  74. {
  75.     gStaticBufferUseCount ++;
  76.     
  77.     GetNextLine();
  78.     FW_END_CONSTRUCTOR
  79. }
  80.     
  81. //----------------------------------------------------------------------------------------
  82. // FW_CPrivTextBuffer::~FW_CPrivTextBuffer
  83. //----------------------------------------------------------------------------------------
  84.  
  85. FW_CPrivTextBuffer::~FW_CPrivTextBuffer()
  86. {
  87.     FW_START_DESTRUCTOR
  88.     
  89.     gStaticBufferUseCount --;
  90.  
  91.     if(fDynamicBufferBase != NULL)
  92.         FW_CMemoryManager::FreeBlock((void*)fDynamicBufferBase);
  93.         
  94. }
  95.  
  96. //----------------------------------------------------------------------------------------
  97. // FW_CPrivTextBuffer::GetTotalLength
  98. //----------------------------------------------------------------------------------------
  99.  
  100. FW_ByteCount FW_CPrivTextBuffer::GetTotalLength() const
  101. {
  102.     // MetroWerks bug workaround [AMB]
  103.     const FW_CString* string = fString;
  104.     
  105.     if (string != NULL)
  106.         return string->GetByteLength();
  107.     
  108.     FW_ASSERT(fReader != NULL);
  109.     return fReader->GetByteLength();
  110. }
  111.  
  112. //----------------------------------------------------------------------------------------
  113. // FW_CPrivTextBuffer::IsDone
  114. //----------------------------------------------------------------------------------------
  115.  
  116. FW_Boolean FW_CPrivTextBuffer::IsDone() const
  117. {
  118.     return fIsDone;
  119. }
  120.     
  121. //----------------------------------------------------------------------------------------
  122. // FW_CPrivTextBuffer::GetNextLine
  123. //----------------------------------------------------------------------------------------
  124.  
  125. void FW_CPrivTextBuffer::GetNextLine()
  126. {
  127.     // the user should not call this method after we told him we're done
  128.     FW_ASSERT(!IsDone());
  129.  
  130.     // MetroWerks bug workaround [AMB]
  131.     const FW_CString* string = fString;
  132.     
  133.     if (string != NULL)
  134.     {
  135.         // we have a string
  136.         if (fCurrentLine == NULL)
  137.         {
  138.             // Strings come as one chunk; therefore, we shouldn't have any on the way in
  139.             fCurrentLine = (FW_Byte*)(const FW_Char*) *string;
  140.             fCurrentLineLength = string->GetByteLength();
  141.             fIsDone = fCurrentLineLength == 0;
  142.         }
  143.         else
  144.         {
  145.             // otherwise, this is the second request, and we're done
  146.             fIsDone = TRUE;
  147.         }
  148.     }
  149.     else
  150.     {
  151.         if (fReader != NULL)
  152.         {
  153.             const FW_Byte* run;
  154.             FW_ByteCount runLen;
  155.             fReader->PeekRunAhead(run, runLen);
  156.             
  157.             if (runLen > 0)
  158.             {
  159.                 if (runLen == fReader->GetByteLength() - fReader->GetPosition())
  160.                 {
  161.                     // the last run in the reader
  162.                     fCurrentLine = (FW_Byte*) run;
  163.                     fCurrentLineLength = runLen;
  164.                     fReader->Advance(fCurrentLineLength);
  165.                     fReader = NULL;
  166.                 }
  167.                 else
  168.                 {
  169.                     // darn, not the last run -- try to find a newline character
  170.                     const FW_Byte* runLimit = run + runLen, *p = run;
  171.                     
  172.                     while (p < runLimit && *p != FW_PlatformNewLineChar)
  173.                         p ++;
  174.                         
  175.                     if (*p == FW_PlatformNewLineChar)
  176.                     {
  177.                         // we found a newline
  178.                         fCurrentLine = (FW_Byte*) run;
  179.                         fCurrentLineLength = p - run + 1;
  180.                         fReader->Advance(fCurrentLineLength);
  181.                     }
  182.                     else
  183.                     {
  184.                         // no newline, consume the current run...
  185.                         ResetBuffer(runLen);
  186.                         FW_CMemoryManager::CopyMemory(run, fCurrentLine, runLen);
  187.                         fCurrentLineLength = runLen;
  188.                         fReader->Advance(fCurrentLineLength);
  189.                         
  190.                         // ...and keep reading
  191.                         FW_Char c;
  192.                         while ((c = fReader->GetCharacterAndAdvance()) != 0)
  193.                         {
  194.                             AppendCharacterToBuffer(c);
  195.                             if (c == FW_PlatformNewLineChar)
  196.                                 break;
  197.                         }
  198.                         
  199.                         if (c == 0)
  200.                             fReader = NULL;
  201.                     }
  202.                 }
  203.                 
  204.             }
  205.             else
  206.                 fReader = NULL;
  207.             
  208. #if 0
  209.             ResetBuffer();
  210.  
  211.             FW_Char c;
  212.             while((c = fReader->GetCharacterAndAdvance()) != 0)
  213.             {
  214.                 AppendCharacterToBuffer(c);
  215.                 if(c == '\n')
  216.                     break;
  217.             }
  218.             
  219.             if(c == 0)
  220.                 fReader = NULL;
  221. #endif                
  222.         }
  223.         else
  224.             fIsDone = TRUE;
  225.     }
  226. }
  227.     
  228. //----------------------------------------------------------------------------------------
  229. // FW_CPrivTextBuffer::GetCurrentLine
  230. //----------------------------------------------------------------------------------------
  231.  
  232. const FW_Byte* FW_CPrivTextBuffer::GetCurrentLine() const
  233. {
  234.     return fCurrentLine;
  235. }
  236.     
  237. //----------------------------------------------------------------------------------------
  238. // FW_CPrivTextBuffer::GetCurrentLineLength
  239. //----------------------------------------------------------------------------------------
  240.  
  241. FW_ByteCount FW_CPrivTextBuffer::GetCurrentLineLength() const
  242. {
  243.     return fCurrentLineLength;
  244. }
  245.     
  246. //----------------------------------------------------------------------------------------
  247. // FW_CPrivTextBuffer::ResetBuffer
  248. //----------------------------------------------------------------------------------------
  249.  
  250. void FW_CPrivTextBuffer::ResetBuffer(FW_ByteCount size)
  251. {
  252.     FW_ASSERT(size != 0);
  253.  
  254.     if(gStaticBufferUseCount == 1 && size <= FW_kStaticBufferSize)
  255.     {
  256.         // the static buffer is not in use yet, use it
  257.         fDynamicBufferBase = NULL;
  258.         fCurrentLine = gStaticBuffer;
  259.         fCurrentBufferSize = FW_kStaticBufferSize;
  260.     }
  261.     else
  262.     {
  263.         // the static buffer is in use, allocate a dynamic buffer
  264.         fDynamicBufferSize = size;
  265.         fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::AllocateBlock(fDynamicBufferSize);
  266.         fCurrentLine = fDynamicBufferBase;
  267.         fCurrentBufferSize = fDynamicBufferSize;
  268.     }
  269.     
  270.     fCurrentLineLength = 0;
  271. }
  272.     
  273. //----------------------------------------------------------------------------------------
  274. // FW_CPrivTextBuffer::AppendCharacterToBuffer
  275. //----------------------------------------------------------------------------------------
  276.  
  277. void FW_CPrivTextBuffer::AppendCharacterToBuffer(FW_Char c)
  278. {
  279.     if(fCurrentLineLength < fCurrentBufferSize)
  280.     {
  281.         // the buffer is still large enough, just stick the character in
  282.         fCurrentLine[fCurrentLineLength] = c;    
  283.     }
  284.     else
  285.     {
  286.         // the buffer ran small
  287.         if(fDynamicBufferBase == NULL)
  288.         {
  289.             // we are switching from a static to a dynamic buffer
  290.             fDynamicBufferSize = 2 * FW_kDynamicBufferSizeIncrement;
  291.             fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::AllocateBlock(fDynamicBufferSize);
  292.             fCurrentLine = fDynamicBufferBase;
  293.             fCurrentBufferSize = fDynamicBufferSize;
  294.             
  295.             // copy the current contents into the dynamic buffer
  296.             ::FW_PrimitiveCopyMemory((const void*)gStaticBuffer, (void*)fDynamicBufferBase, FW_kStaticBufferSize);
  297.         }
  298.         else
  299.         {
  300.             // just reallocate the dynamic buffer
  301.             fDynamicBufferSize += FW_kDynamicBufferSizeIncrement;
  302.             fDynamicBufferBase = (FW_Byte*) FW_CMemoryManager::ResizeBlock((void*)fDynamicBufferBase, fDynamicBufferSize);
  303.             fCurrentBufferSize = fDynamicBufferSize;
  304.         }
  305.     }
  306.     
  307.     fCurrentLineLength ++;
  308. }
  309.  
  310. //========================================================================================
  311. // Global Method PrivGetStringSegment
  312. //========================================================================================
  313. //
  314. //      Used by word-wrapping text measurement and drawing methods
  315. //
  316. //      str         - the string we're wrapping
  317. //      len         - length of the string
  318. //      segStart    - start of the segment that should be drawn
  319. //      segLen      - length of the segement that should be drawn
  320. //      maxWidth    - max width that the string can be when drawn
  321. //      actualWidth - the actual width of the string
  322. //      wordWrap    - should we try to wrap text or just draw it in one piece
  323. //        wordBreak   - if the first word doesn't fit, should we break it?
  324.  
  325. FW_Boolean    PrivGetStringSegment(ODPlatformCanvas platformCanvas,
  326.                                 const char* str,
  327.                                     FW_ByteCount len,
  328.                                     FW_BytePosition& segStart,
  329.                                     FW_ByteCount& segLen,
  330.                                     FW_PlatformCoordinate maxWidth,
  331.                                    FW_PlatformCoordinate& actualWidth,
  332.                                     FW_Boolean wordWrap,
  333.                                     FW_Boolean wordBreak)
  334. {
  335.     enum
  336.     {
  337.         kSpace = ' ',
  338. #ifdef FW_BUILD_WIN
  339.         kCR = '\r',
  340. #endif
  341.         kLF = '\n'
  342.     };
  343.  
  344.     segStart = 0;
  345.     segLen = 0;
  346.  
  347.     // if we encountered an end-line during the previous call, "str" will point to a newline char
  348. #ifdef FW_BUILD_WIN
  349.     if (*str == kCR && len > 0)
  350.     {
  351.         str++;
  352.         segStart++;
  353.         len--;
  354.     }
  355. #endif
  356.     if (*str == kLF && len > 0)
  357.     {
  358.         str++;
  359.         segStart++;
  360.         len--;
  361.     }
  362.  
  363.     // skip the leading spaces
  364.     while (*str == kSpace && len > 0)
  365.     {
  366.         str++;
  367.         segStart++;
  368.         len--;
  369.     }
  370.  
  371.     if (len == 0)
  372.         return FALSE;
  373.  
  374. #ifdef FW_BUILD_WIN
  375.     SIZE size;
  376. #endif
  377.  
  378.     if (!wordWrap)
  379.     {
  380.         // return the whole string in one chunk
  381.         segLen = len;
  382. #ifdef FW_BUILD_WIN
  383.         ::GetTextExtentPoint(platformCanvas, str, len, &size);
  384.         actualWidth = size.cx;
  385. #endif
  386. #ifdef FW_BUILD_MAC
  387.         actualWidth = ::TextWidth(Ptr(str), 0, len);
  388. #endif
  389.     }
  390.     else
  391.     {
  392.         // break the string into chunks
  393.         FW_PlatformCoordinate accumWidth = 0;
  394.         FW_PlatformCoordinate newWidth;
  395.         FW_PlatformCoordinate wordWidth;
  396.         const char* s = str;
  397.         const char* wordEnd = NULL;
  398.  
  399.         segLen = 0;
  400.  
  401.         while (len > 0)
  402.         {
  403.             // check if we are at the end of a word
  404.             if (*s == kSpace)
  405.             {
  406.                 if (*(s - 1) != kSpace)
  407.                 {
  408.                     wordEnd = s;
  409.                     wordWidth = accumWidth;
  410.                 }
  411.             }
  412.  
  413.             // check if we have a line terminator
  414. #ifdef FW_BUILD_WIN
  415.             if (*s == kCR || *s == kLF)
  416. #endif
  417. #ifdef FW_BUILD_MAC
  418.             if (*s == kLF)
  419. #endif
  420.             {
  421.                 wordEnd = s;
  422.                 wordWidth = accumWidth;
  423.                 break;
  424.             }
  425.  
  426.             // add the current char width
  427. #ifdef FW_BUILD_WIN
  428.             ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
  429.             newWidth = size.cx;
  430. #endif
  431. #ifdef FW_BUILD_MAC
  432.             newWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
  433. #endif
  434.             if (newWidth > maxWidth)
  435.                 break;
  436.  
  437.             accumWidth = newWidth;
  438.  
  439.             // advance to the next character
  440.             s++;
  441.             len--;
  442.         }
  443.  
  444.         // the whole string fit just fine
  445.         if (len == 0)
  446.         {
  447.             wordEnd = s;
  448.             wordWidth = accumWidth;
  449.         }
  450.  
  451.         // the first character was too wide
  452.         if (s == str)
  453.         {
  454.             // ... but it was the first character, so draw it anyways!
  455.             s++;
  456.             len--;
  457. #ifdef FW_BUILD_WIN
  458.             ::GetTextExtentPoint(platformCanvas, str, 1, &size);
  459.             newWidth = size.cx;
  460. #endif
  461.  
  462. #ifdef FW_BUILD_MAC
  463.             newWidth = ::TextWidth(Ptr(str), 0, 1);
  464. #endif
  465.         }
  466.  
  467.         // the first word didn't fit...
  468.         if (wordEnd == NULL)
  469.         {
  470.             if (!wordBreak)
  471.             {
  472.                 // it's not ok to break the first word, keep looking
  473.                 while (len > 0 && *s != ' ')
  474.                 {
  475. #ifdef FW_BUILD_WIN
  476.                     SIZE size;
  477.                     ::GetTextExtentPoint(platformCanvas, str, s - str + 1, &size);
  478.                     accumWidth = size.cx;
  479. #endif
  480. #ifdef FW_BUILD_MAC
  481.                     accumWidth = ::TextWidth(Ptr(str), 0, s - str + 1);
  482. #endif
  483.                     s++;
  484.                     len--;
  485.                 }
  486.             }
  487.  
  488.             wordWidth = accumWidth;
  489.             wordEnd = s;
  490.         }
  491.  
  492.         segLen = wordEnd - str;
  493.         actualWidth = wordWidth;
  494.     }
  495.  
  496.     return TRUE;
  497. }
  498.